//
// Created by 86135 on 2025-06-05.
//

#include "lexer.h"
#include <stdbool.h>
#include <string.h>

//// 词法分析器
//typedef struct {
//    const char* start;   // Token的起始位置
//    const char* current; // 当前位置
//    int line;            // 当前的行数
//} Lexer;

// 全局变量
Lexer lexer;

void initLexer(const char* source){
    // 初始化lexer
    lexer.current = source;
    lexer.start = source;
    lexer.line = 1;
}
void resetLexer() {
    lexer.line = 1;  // 重置行号计数器
}
/********************************************************************************************
 *                                         辅助方法										    *
 ********************************************************************************************/
static bool isAlpha(char c) {
    return (c >= 'a' && c <= 'z') ||
           (c >= 'A' && c <= 'Z') ||
           c == '_';
}

static bool isDigit(char c) {
    return c >= '0' && c <= '9';
}

static bool isAtEnd() {
    return *lexer.current == '\0';
}

//先获取当前字符，再移动
static char advance() {
    return *lexer.current++;
}
//查看当前字符
static char peek() {
    return *lexer.current;
}
//查看下一个字符
static char peekNext() {
    if (isAtEnd()) return '\0';
    return *(lexer.current + 1);
}

// 判断字符是否匹配，如果匹配则前进指针
static bool match(char expected) {
    if (isAtEnd()) return false;
    if (*lexer.current != expected) return false;
    lexer.current++;
    return true;
}
// 跳过空白字符和注释
static void skipWhitespace() {
    // 跳过空白字符: ' ', '\r', '\t', '\n'和注释
    while(1) {
        char c = peek();
        switch (c) {
            case ' ':
            case '\r':
            case '\t':
                advance();
                break;
            case '\n':
                lexer.line++;
                advance();
                break;
            case '/':
                if (peekNext() == '/') {
                    // 单行注释
                    while (peek() != '\n' && !isAtEnd())
                        advance();
                } else {
                    return;
                }
                break;
            default:
                return;
        }
    }
}

// 传入TokenType, 创建对应类型的Token，并返回。
static Token makeToken(TokenType type) {
    Token token;
    token.type = type;
    token.start = lexer.start;
    token.length = (int)(lexer.current - lexer.start);
    token.line = lexer.line;
    return token;
}

// 遇到不能解析的情况时，我们创建一个ERROR Token. 比如：遇到@，$等符号时，比如字符串，字符没有对应的右引号时。
static Token errorToken(const char* message) {
    Token token;
    token.type = TOKEN_ERROR;
    token.start = message;
    token.length = (int)strlen(message);
    token.line = lexer.line;
    return token;
}
//检查关键字用的对比函数
//start = 对比标识符起点偏移量, length = 要比较的长度, rest = 剩余字符串
static TokenType checkKeyword(int start, int length, const char* rest, TokenType type) {
    int len = (int)(lexer.current - lexer.start);
    if (start + length == len && memcmp(lexer.start + start, rest, length) == 0) {
        return type;
    }
    return TOKEN_IDENTIFIER;
}
/********************************************************************************************
 *                                         识别函数										    *
 ********************************************************************************************/
// 判断当前Token到底是标识符还是关键字
static TokenType identifierType() {
    char c = lexer.start[0];
    int len = (int)(lexer.current - lexer.start);       //当前token长度
    // 用switch语句实现Trie树
    switch (c) {
        case 'b': return checkKeyword(1, 4, "reak", TOKEN_BREAK);
            // ... // TODO
        case 'c':
            c = lexer.start[1];
            switch (c)
            {
                case 'a':
                    return checkKeyword(2, 2, "se", TOKEN_CASE);
                case 'h':
                    return checkKeyword(2, 2, "ar", TOKEN_CHAR);
                case 'o':
                    if(lexer.start[2] != 'n')    return TOKEN_IDENTIFIER;
                    c = lexer.start[3];
                    switch (c)
                    {
                        case 't':
                            return checkKeyword(4, 4, "inue", TOKEN_CONTINUE);
                        case 's':
                            return checkKeyword(4, 1, "t", TOKEN_CONST);
                        default:    return TOKEN_IDENTIFIER;
                    }
                default:    return TOKEN_IDENTIFIER;
            }
        case 'd':
            c = lexer.start[1];
            switch (c)
            {
                case 'e':
                    return checkKeyword(2, 5, "fault", TOKEN_DEFAULT);
                case 'o':
                    if (len == 2)    return TOKEN_DO;
                    if (lexer.start[2] == 'u')
                        return checkKeyword(3, 3, "ble", TOKEN_DOUBLE);
                default:    return TOKEN_IDENTIFIER;
            }
        case 'e':
            c = lexer.start[1];
            switch (c)
            {
                case 'n':
                    return checkKeyword(2, 2, "um", TOKEN_ENUM);
                case 'l':
                    return checkKeyword(2, 2, "se", TOKEN_ELSE);
                default:    return TOKEN_IDENTIFIER;
            }
        case 'f':
            c = lexer.start[1];
            switch (c)
            {
                case 'l':
                    return checkKeyword(2, 3, "oat", TOKEN_FLOAT);
                case 'o':
                    return checkKeyword(2, 1, "r", TOKEN_FOR);
                default:    return TOKEN_IDENTIFIER;
            }
        case 'g':
            return checkKeyword(1, 3, "oto", TOKEN_GOTO);
        case 'i':
            c = lexer.start[1];
            switch (c)
            {
                case 'f':
                    return checkKeyword(2, 0, "", TOKEN_IF);
                case 'n':
                    return checkKeyword(2, 1, "t", TOKEN_INT);
                default:    return TOKEN_IDENTIFIER;
            }
        case 'l':
            return checkKeyword(1, 3, "ong", TOKEN_LONG);
        case 'r':
            return checkKeyword(1, 5, "eturn", TOKEN_RETURN);
        case 's':
            c = lexer.start[1];
            switch (c)
            {
                case 'h':
                    return checkKeyword(2, 3, "ort", TOKEN_SHORT);
                case 'i':
                    c = lexer.start[2];
                    switch (c)
                    {
                        case 'g':
                            return checkKeyword(3, 3, "ned", TOKEN_SIGNED);
                        case 'z':
                            return checkKeyword(3, 3, "eof", TOKEN_SIZEOF);
                        default:    return TOKEN_IDENTIFIER;
                    }
                case 't':
                    return checkKeyword(2, 4, "ruct", TOKEN_STRUCT);
                case 'w':
                    return checkKeyword(2, 4, "itch", TOKEN_SWITCH);
                default:    return TOKEN_IDENTIFIER;
            }
        case 't':
            return checkKeyword(1, 6, "ypedef", TOKEN_TYPEDEF);
        case 'u':
            if (lexer.start[1] != 'n')    return TOKEN_IDENTIFIER;
            c = lexer.start[2];
            switch (c)
            {
                case 's':
                    return checkKeyword(3, 5, "igned", TOKEN_UNSIGNED);
                case 'i':
                    return checkKeyword(3, 2, "on", TOKEN_UNION);
                default:
                    return TOKEN_IDENTIFIER;
            }

        case 'v':
            return checkKeyword(1, 3, "oid", TOKEN_VOID);
        case 'w':
            return checkKeyword(1, 4, "hile", TOKEN_WHILE);
        default:
            return TOKEN_IDENTIFIER;
    }

    // identifier
//    return TOKEN_IDENTIFIER;
}

// 识别标识符
static Token identifier() {
    // IDENTIFIER包含: 字母，数字和下划线
    while (isAlpha(peek()) || isDigit(peek()))
        advance();
    // 这样的Token可能是标识符, 也可能是关键字, identifierType()是用来确定Token类型的
    return makeToken(identifierType());
}

// 识别数字
static Token number() {
    // 简单起见，我们将NUMBER的规则定义如下:
    // 1. NUMBER可以包含数字和最多一个'.'号
    // 2. '.'号前面要有数字
    // 3. '.'号后面也要有数字
    while (isDigit(peek())) advance();

    // 处理小数部分
    if (peek() == '.' && isDigit(peekNext())) {
        // 消耗小数点
        advance();

        while (isDigit(peek())) advance();
    }
    return makeToken(TOKEN_NUMBER);
}

// 识别字符
static Token character() {
//    advance(); // 消耗单引号
    if (isAtEnd())
        return errorToken("Character formatting error!");
    char c = advance();
    // 处理转义字符
    if (c == '\\') {
        if (isAtEnd())
            return errorToken("Unterminated escape sequence!");
        c = advance();
        // 这里可以添加更多转义字符处理
        switch (c) {
            case 'n': c = '\n'; break;
            case 't': c = '\t'; break;
            case 'r': c = '\r'; break;
            case '0': c = '\0'; break;
                // 其他转义字符...todo
            default:    break;
        }
    }
    if (peek() != '\'')
        return errorToken("Character formatting error!");
    advance(); // 消耗单引号

    return makeToken(TOKEN_CHARACTER);
}

// 识别字符串
static Token string() {
    // 字符串以"开头，以"结尾，而且不能跨行，目前不可以，以后修改
    while (!isAtEnd() && peek() != '"')
    {
        if (peek() == '\n')
            return errorToken("Strings cannot span lines!");
        advance();
    }
    if (isAtEnd())
        return errorToken("String formatting error!");

    // 消耗闭合引号
    advance();
    return makeToken(TOKEN_STRING);
}
/********************************************************************************************
 *                                           分词		 								    *
 ********************************************************************************************/
// 识别token，返回下一个token
Token lexerIdentifier(){
    // 跳过前置空白字符和注释
    skipWhitespace();
    // 记录下一个Token的起始位置
    lexer.start = lexer.current;

    if (isAtEnd()) return makeToken(TOKEN_EOF);

    char c = advance(); //读取字符，指针后移
    if (isAlpha(c)) return identifier();
    if (isDigit(c)) return number();

    switch (c) {
            // single-character tokens
        case '(': return makeToken(TOKEN_LEFT_PAREN);
        case ')': return makeToken(TOKEN_RIGHT_PAREN);
        case '[': return makeToken(TOKEN_LEFT_BRACKET);
        case ']': return makeToken(TOKEN_RIGHT_BRACKET);
        case '{': return makeToken(TOKEN_LEFT_BRACE);
        case '}': return makeToken(TOKEN_RIGHT_BRACE);
        case ',': return makeToken(TOKEN_COMMA);
        case '.': return makeToken(TOKEN_DOT);
        case ';': return makeToken(TOKEN_SEMICOLON);
        case '~': return makeToken(TOKEN_TILDE);
            // ...	// TODO

            // one or two characters tokens
        case '+':
            if (match('+')) return makeToken(TOKEN_PLUS_PLUS);
            else if (match('=')) return makeToken(TOKEN_PLUS_EQUAL);
            else return makeToken(TOKEN_PLUS);
        case '-':
            if (match('-')) return makeToken(TOKEN_MINUS_MINUS);
            else if (match('=')) return makeToken(TOKEN_MINUS_EQUAL);
            else if (match('>')) return makeToken(TOKEN_MINUS_GREATER);
            else return makeToken(TOKEN_MINUS);
        case '*':
            if (match('=')) return makeToken(TOKEN_STAR_EQUAL);
            else return makeToken(TOKEN_STAR);
        case '/':
            if (match('=')) return makeToken(TOKEN_SLASH_EQUAL);
            else return makeToken(TOKEN_SLASH);
        case '%':
            if (match('=')) return makeToken(TOKEN_PERCENT_EQUAL);
            else return makeToken(TOKEN_PERCENT);
        case '&':
            if (match('=')) return makeToken(TOKEN_AMPER_EQUAL);
            else if (match('&')) return makeToken(TOKEN_AMPER_AMPER);
            else return makeToken(TOKEN_AMPER);
        case '|':
            if (match('=')) return makeToken(TOKEN_PIPE_EQUAL);
            else if (match('|')) return makeToken(TOKEN_PIPE_PIPE);
            else return makeToken(TOKEN_PIPE);
        case '^':
            if (match('=')) return makeToken(TOKEN_HAT_EQUAL);
            else return makeToken(TOKEN_HAT);
        case '=':
            if (match('=')) return makeToken(TOKEN_EQUAL_EQUAL);
            else return makeToken(TOKEN_EQUAL);
        case '!':
            if (match('=')) return makeToken(TOKEN_BANG_EQUAL);
            else return makeToken(TOKEN_BANG);
        case '<':
            if (match('=')) return makeToken(TOKEN_LESS_EQUAL);
            else if (match('<')) return makeToken(TOKEN_LESS_LESS);
            else return makeToken(TOKEN_LESS);
        case '>':
            if (match('=')) return makeToken(TOKEN_GREATER_EQUAL);
            else if (match('>')) return makeToken(TOKEN_GREATER_GREATER);
            else return makeToken(TOKEN_GREATER);

            // ... // TODO

            // various-character tokens
        case '"': return string();
        case '\'': return character();
        default:
            return errorToken("Unexpected character.");
    }
}